//
//  EchoServer.m
//  EchoServer
//
//  Created by Arthur on 15/6/5.
//  Copyright (c) 2015年 Arthur. All rights reserved.
//

#import "EchoServer.h"
#import <CoreFoundation/CoreFoundation.h>
#import <sys/socket.h>
#import <netinet/in.h>


#ifndef LISTENQ
#define LISTENQ 1024
#endif

void receiveData(CFSocketRef sRef, CFSocketCallBackType
                 cType,CFDataRef address, const void *data, void *info)
{
    CFDataRef df = (CFDataRef) data;
    long len = CFDataGetLength(df);
    if(len <= 0) return;
    UInt8 buf[len];
    CFRange range = CFRangeMake(0,len);
    CFDataGetBytes(df, range, buf);
    buf[len]='\0';
    NSString *str = [[NSString alloc] initWithData:(__bridge NSData*)data
                                          encoding:NSASCIIStringEncoding];
    NSLog(@"Received:  %@",str);
    [[NSNotificationCenter defaultCenter]
     postNotificationName:@"posttext" object:str];
    CFSocketSendData(sRef, address, df, 0);  // Echo back
}

void acceptConnection(CFSocketRef sRef, CFSocketCallBackType
                      cType, CFDataRef address, const void *data, void *info)
{
    CFSocketNativeHandle csock = *(CFSocketNativeHandle *)data;
    CFSocketRef sn;
    CFRunLoopSourceRef source;
    const CFSocketContext context = {0, NULL, NULL, NULL, NULL};
    sn = CFSocketCreateWithNative(NULL, csock,
                                  kCFSocketDataCallBack, receiveData, &context);
    source = CFSocketCreateRunLoopSource(NULL, sn, 0);
    CFRunLoopAddSource(CFRunLoopGetCurrent(), source,
                       kCFRunLoopDefaultMode);
    CFRelease(source);
    CFRelease(sn);
}

@implementation EchoServer


-(instancetype)initOnPort:(int)port{
    struct sockaddr_in serverAddr;
    CFRunLoopSourceRef source;
    const CFSocketContext ctx = {0,NULL,NULL,NULL,NULL};
    self.errorCode = NOERROR;
    if((self.lisenfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))){
        self.errorCode = SOCKETERROR;
    }
    else{
        memset(&serverAddr, 0, sizeof(serverAddr));
        serverAddr.sin_family = AF_INET;
        serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        serverAddr.sin_port = htons(port);
        if(bind(self.lisenfd,(struct sockaddr*)&serverAddr,sizeof(serverAddr) < 0)){
            self.errorCode = BINDERROR;
            
        }
        else{
            if (listen(self.lisenfd, LISTENQ) < 0) {
                self.errorCode =  LISTENERROR;
            }
            else{
                self.socketRef = CFSocketCreateWithNative(NULL, self.lisenfd, kCFSocketConnectCallBack, acceptConnection, &ctx);
                if(self.socketRef == NULL){
                    self.errorCode = CFSOCKETCREATEERROR;
                }
                else{
                    source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, self.socketRef, 0);
                    CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
                    
                    CFRelease(source);
                    
                    CFRunLoopRun();
                }
            }
        }
    }
    return self;
}
@end
